package blogger

import (
	"binterfaces/ilogger"
	"blogger/formatter"
	"io"
	"os"
	"path/filepath"
	"sync"
)

// LoggerOption 日志参数配置项
type LoggerOption struct {
	Prefix       string             // 日志前缀
	Level        ilogger.LogLevel   // 日志等级
	Formatter    ilogger.IFormatter // 格式化
	TimeFormat   string             // 输出的时间格式化
	lock         ilogger.ILock
	out          io.Writer
	filename     string
	Hooks        ilogger.IHook       // 钩子函数
	ReportCaller bool                // 是否输出调用信息
	entryPool    sync.Pool           // 对象池
	bufPool      ilogger.IBufferPool // 缓冲池
	LogPath      string              // 日志文件的基础路径
	MaxSize      int                 // 单日志文件最大阈值 MB 单位
	Compress     bool                // 是否压缩
}

type Option func(*LoggerOption)

func WithPrefix(prefix string) Option {
	return func(o *LoggerOption) {
		o.Prefix = prefix
	}
}

func WithLevel(level ilogger.LogLevel) Option {
	return func(o *LoggerOption) {
		o.Level = level
	}
}

func WithFormatter(format ilogger.LogFormat, args ...ilogger.IFormatter) Option {
	var f ilogger.IFormatter
	switch format {
	case ilogger.LogFormatJson:
		f = formatter.DefaultJsonFormatter()
	case ilogger.LogFormatCustom:
		if len(args) > 0 {
			f = args[0]
		} else {
			panic("日志格式未定义")
		}
	case ilogger.LogFormatText:
		f = formatter.DefaultTextFormatter()
	default:
		f = formatter.DefaultTextFormatter()
	}
	return func(o *LoggerOption) {
		o.Formatter = f
	}
}

func WithTimeFormat(timeFormat string) Option {
	return func(o *LoggerOption) {
		o.TimeFormat = timeFormat
	}
}

func WithBasePath(basePath string) Option {
	return func(o *LoggerOption) {
		if basePath == "" {
			o.LogPath = os.TempDir()
			return
		}
		o.LogPath = basePath
	}
}

func DefaultLogger(options ...Option) *BootLogger {
	// 默认值
	o := &LoggerOption{
		out:          io.MultiWriter(os.Stderr),
		Prefix:       ilogger.DefaultPrefix,
		Level:        ilogger.DefaultLevel,
		Formatter:    formatter.DefaultJsonFormatter(),
		lock:         NewLock(),
		Hooks:        DefaultHooks(),
		bufPool:      DefaultBufPool(),
		ReportCaller: true,
		MaxSize:      5,
		Compress:     true,
	}

	for _, fn := range options {
		fn(o)
	}

	name := filepath.Join(o.LogPath, filepath.Base(os.Args[0])+".log")
	o.filename = name

	info, err := os.Stat(name)
	if os.IsNotExist(err) {
		dir := filepath.Dir(name)
		if err := os.MkdirAll(dir, 0755); err != nil {
			panic(err)
		}
		file, err := os.OpenFile(name, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
		if err != nil {
			panic("创建日志文件失败" + err.Error())
		}
		o.out = io.MultiWriter(os.Stderr, file)
		return &BootLogger{
			option: o,
			file:   file,
			size:   0,
		}
	}
	if err != nil {
		panic("创建日志文件失败" + err.Error())
	}
	file, err := os.OpenFile(name, os.O_APPEND|os.O_WRONLY, 0644)
	o.out = io.MultiWriter(os.Stderr, file)
	logger := &BootLogger{
		option: o,
		file:   file,
		size:   info.Size(),
	}
	logger.option.entryPool = sync.Pool{New: func() any {
		return NewEntry(logger)
	}}
	return logger
}
